package platform

import (
	"log"
	"sync"
	"syscall"
	"unsafe"
)

const (
	WH_KEYBOARD_LL = 13
	WM_KEYDOWN     = 256
	WM_KEYUP       = 257
	WM_SYSKEYDOWN  = 260
	WM_SYSKEYUP    = 261

	VK_CAPITAL = 0x14 // CapsLock
	VK_ESCAPE  = 0x1B // Escape
	VK_CONTROL = 0x11 // Ctrl
	VK_MENU    = 0x12 // Alt
	VK_SHIFT   = 0x10 // Shift

	INPUT_KEYBOARD = 1

	// 功能键
	VK_F1  = 0x70
	VK_F2  = 0x71
	VK_F3  = 0x72
	VK_F4  = 0x73
	VK_F5  = 0x74
	VK_F6  = 0x75
	VK_F7  = 0x76
	VK_F8  = 0x77
	VK_F9  = 0x78
	VK_F10 = 0x79
	VK_F11 = 0x7A
	VK_F12 = 0x7B

	// 导航键
	VK_TAB    = 0x09
	VK_RETURN = 0x0D
	VK_SPACE  = 0x20
	VK_PRIOR  = 0x21 // PgUp
	VK_NEXT   = 0x22 // PgDn
	VK_END    = 0x23
	VK_HOME   = 0x24
	VK_LEFT   = 0x25
	VK_UP     = 0x26
	VK_RIGHT  = 0x27
	VK_DOWN   = 0x28
	VK_INSERT = 0x2D
	VK_DELETE = 0x2E
	VK_BACK   = 0x08 // Backspace

	// 修饰键 - 添加左右区分
	VK_LCONTROL = 0xA2 // 左 Ctrl
	VK_RCONTROL = 0xA3 // 右 Ctrl
	VK_LALT     = 0xA4 // 左 Alt
	VK_RALT     = 0xA5 // 右 Alt
	VK_LSHIFT   = 0xA0 // 左 Shift
	VK_RSHIFT   = 0xA1 // 右 Shift
	VK_LWIN     = 0x5B // 左 Win
	VK_RWIN     = 0x5C // 右 Win

	// 按键标志位
	LLKHF_EXTENDED = 0x01
	LLKHF_INJECTED = 0x10
	LLKHF_ALTDOWN  = 0x20
	LLKHF_UP       = 0x80
)

var (
	keyboardHook HHOOK
	hookMutex    sync.Mutex
	isSimulating bool
)

type (
	HHOOK    uintptr
	HOOKPROC func(int, WPARAM, LPARAM) LRESULT

	KBDLLHOOKSTRUCT struct {
		VkCode      DWORD
		ScanCode    DWORD
		Flags       DWORD
		Time        DWORD
		DwExtraInfo ULONG_PTR
	}

	WPARAM    uintptr
	LPARAM    uintptr
	LRESULT   uintptr
	DWORD     uint32
	ULONG_PTR uintptr

	INPUT struct {
		Type    uint32
		Ki      KEYBDINPUT
		Padding uint64
	}

	KEYBDINPUT struct {
		WVk         uint16
		WScan       uint16
		DwFlags     uint32
		Time        uint32
		DwExtraInfo uintptr
	}
)

type KeyboardHook struct {
	manager *KeyboardManager
}

func NewKeyboardHook() *KeyboardHook {
	return &KeyboardHook{}
}

func (k *KeyboardHook) Start() error {
	hookMutex.Lock()
	defer hookMutex.Unlock()

	if keyboardHook != 0 {
		return nil
	}

	// 设置键盘钩子
	hook, err := setWindowsHookEx(
		WH_KEYBOARD_LL,
		keyboardProc,
		0,
		0,
	)
	if err != nil {
		return err
	}

	keyboardHook = hook
	return nil
}

func (k *KeyboardHook) Stop() {
	hookMutex.Lock()
	defer hookMutex.Unlock()

	if keyboardHook != 0 {
		unhookWindowsHookEx(keyboardHook)
		keyboardHook = 0
	}
}

func keyboardProc(nCode int, wparam WPARAM, lparam LPARAM) LRESULT {
	if nCode >= 0 {
		if isSimulating {
			return callNextHookEx(keyboardHook, nCode, wparam, lparam)
		}

		kbdStruct := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lparam))
		pressedKey := kbdStruct.VkCode

		// 检查是否是重复按键事件
		isRepeat := kbdStruct.Flags&0x40 != 0 // 检查 LLKHF_REPEAT 标志位

		// 处理按键按下和松开事件
		switch wparam {
		case WM_KEYDOWN, WM_SYSKEYDOWN:
			// 只处理非重复的按键按下事件
			if !isRepeat {
				if handled := handleKeyEvent(pressedKey, true); handled {
					return 1
				}
			} else {
				// 对于重复事件，仍然需要模拟按键，但不打印日志
				if handled := handleKeyEvent(pressedKey, true, true); handled {
					return 1
				}
			}
		case WM_KEYUP, WM_SYSKEYUP:
			if handled := handleKeyEvent(pressedKey, false); handled {
				return 1
			}
		}
	}

	return callNextHookEx(keyboardHook, nCode, wparam, lparam)
}

// 处理按键事件
func handleKeyEvent(pressedKey DWORD, isKeyDown bool, skipLog ...bool) bool {
	// 获取当前配置
	manager := GetKeyboardManager()
	manager.mutex.RLock()
	cfg := manager.config
	manager.mutex.RUnlock()

	if cfg != nil && len(cfg.Mappings) > 0 {
		// 检查所有映射
		for _, mapping := range cfg.Mappings {
			sourceKey := getVirtualKeyCode(mapping.SourceKey)
			if sourceKey == 0 {
				if len(skipLog) == 0 || !skipLog[0] {
					log.Printf("未知的源按键: %s\n", mapping.SourceKey)
				}
				continue
			}

			if pressedKey == sourceKey {
				targetKey := getVirtualKeyCode(mapping.DestinationKey)
				if targetKey == 0 {
					if len(skipLog) == 0 || !skipLog[0] {
						log.Printf("未知的目标按键: %s\n", mapping.DestinationKey)
					}
					continue
				}

				// 只在非跳过日志时记录
				if len(skipLog) == 0 || !skipLog[0] {
					var actualSource string
					switch pressedKey {
					case VK_LCONTROL:
						actualSource = "左Ctrl"
					case VK_RCONTROL:
						actualSource = "右Ctrl"
					case VK_LALT:
						actualSource = "左Alt"
					case VK_RALT:
						actualSource = "右Alt"
					case VK_LSHIFT:
						actualSource = "左Shift"
					case VK_RSHIFT:
						actualSource = "右Shift"
					case VK_LWIN:
						actualSource = "左Win"
					case VK_RWIN:
						actualSource = "右Win"
					default:
						actualSource = mapping.SourceKey
					}

					if isKeyDown {
						log.Printf("触发按键映射(按下): %s(%s) -> %s\n", actualSource, mapping.SourceKey, mapping.DestinationKey)
					} else {
						log.Printf("触发按键映射(松开): %s(%s) -> %s\n", actualSource, mapping.SourceKey, mapping.DestinationKey)
					}
				}

				simulateKeyEvent(targetKey, isKeyDown)
				return true
			}
		}
	}
	return false
}

// 模拟单个按键事件（按下或松开）
func simulateKeyEvent(keyCode DWORD, isKeyDown bool) {
	isSimulating = true
	defer func() {
		isSimulating = false
	}()

	input := INPUT{
		Type: INPUT_KEYBOARD,
		Ki: KEYBDINPUT{
			WVk: uint16(keyCode),
		},
	}

	if !isKeyDown {
		input.Ki.DwFlags = 0x0002 // KEYEVENTF_KEYUP
	}

	user32.NewProc("SendInput").Call(
		uintptr(1),
		uintptr(unsafe.Pointer(&input)),
		uintptr(unsafe.Sizeof(input)),
	)
}

// 修改原来的 simulateKey 函数为按下+松开的组合
func simulateKey(keyCode DWORD) {
	simulateKeyEvent(keyCode, true)  // 按下
	simulateKeyEvent(keyCode, false) // 松开
}

// 新增：获取虚拟键码的辅助函数
func getVirtualKeyCode(keyName string) DWORD {
	switch keyName {
	case "CapsLock":
		return VK_CAPITAL
	case "Esc", "Escape":
		return VK_ESCAPE
	case "LCtrl":
		return VK_LCONTROL
	case "RCtrl":
		return VK_RCONTROL
	case "LAlt":
		return VK_LALT
	case "RAlt":
		return VK_RALT
	case "LShift":
		return VK_LSHIFT
	case "RShift":
		return VK_RSHIFT
	case "LWin":
		return VK_LWIN
	case "RWin":
		return VK_RWIN
	case "Tab":
		return VK_TAB
	case "Space":
		return VK_SPACE
	case "Enter":
		return VK_RETURN
	case "Backspace":
		return VK_BACK
	case "Insert":
		return VK_INSERT
	case "Delete":
		return VK_DELETE
	case "Home":
		return VK_HOME
	case "End":
		return VK_END
	case "PgUp":
		return VK_PRIOR
	case "PgDn":
		return VK_NEXT
	case "Left":
		return VK_LEFT
	case "Right":
		return VK_RIGHT
	case "Up":
		return VK_UP
	case "Down":
		return VK_DOWN
	case "F1":
		return VK_F1
	case "F2":
		return VK_F2
	case "F3":
		return VK_F3
	case "F4":
		return VK_F4
	case "F5":
		return VK_F5
	case "F6":
		return VK_F6
	case "F7":
		return VK_F7
	case "F8":
		return VK_F8
	case "F9":
		return VK_F9
	case "F10":
		return VK_F10
	case "F11":
		return VK_F11
	case "F12":
		return VK_F12
	default:
		return 0
	}
}

func setWindowsHookEx(idHook int, lpfn HOOKPROC, hMod uint32, dwThreadId uint32) (HHOOK, error) {
	ret, _, err := procSetWindowsHookEx.Call(
		uintptr(idHook),
		syscall.NewCallback(lpfn),
		uintptr(hMod),
		uintptr(dwThreadId),
	)
	if ret == 0 {
		return 0, err
	}
	return HHOOK(ret), nil
}

func unhookWindowsHookEx(hhk HHOOK) error {
	ret, _, err := procUnhookWindowsHookEx.Call(uintptr(hhk))
	if ret == 0 {
		return err
	}
	return nil
}

func callNextHookEx(hhk HHOOK, nCode int, wparam WPARAM, lparam LPARAM) LRESULT {
	ret, _, _ := procCallNextHookEx.Call(
		uintptr(hhk),
		uintptr(nCode),
		uintptr(wparam),
		uintptr(lparam),
	)
	return LRESULT(ret)
}
